"""
简单的模型调用模块 - 用于需求分析
支持通过 .env 环境变量调用 DeepSeek 或 Moonshot 模型
优先顺序：MOONSHOT_API_KEY -> DEEPSEEK_API_KEY（也可用 MODEL_PROVIDER 显式指定）
"""
import os
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
from typing import List, Dict, Any
import json

# 加载最近的 .env（从当前目录向上查找）
_ = load_dotenv(find_dotenv())

COMMON_FEATURE_SUGGESTIONS: Dict[str, List[str]] = {
    "工具函数": ["lodash", "ramda"],
    "日期处理": ["dayjs", "moment"],
    "测试": ["jest", "@testing-library/dom"],
    "质量保障": ["eslint", "prettier"],
}

FRAMEWORK_FEATURE_SUGGESTIONS: Dict[str, Dict[str, List[str]]] = {
    "react": {
        "文件上传/处理": ["react-dropzone", "@ant-design/upload"],
        "富文本编辑": ["@ant-design/editor", "react-quill"],
        "图表可视化": ["recharts", "@ant-design/charts"],
        "表单处理": ["react-hook-form", "formik"],
        "HTTP请求": ["axios"],
        "状态管理": ["@reduxjs/toolkit", "react-redux", "zustand"],
        "日期处理": ["dayjs", "date-fns"],
        "拖拽功能": ["react-dnd", "@dnd-kit/core"],
    },
    "vue": {
        "HTTP请求": ["axios"],
        "状态管理": ["vuex"],
        "路由管理": ["vue-router"],
        "图表可视化": ["vue-echarts"],
        "国际化": ["vue-i18n"],
        "拖拽功能": ["vuedraggable"],
    },
    "vue2": {
        "UI组件": ["element-ui", "iview"],
        "文件上传/处理": ["vue-upload-component"],
        "富文本编辑": ["vue-quill-editor"],
        "表单处理": ["vee-validate", "vuelidate"],
        "状态管理": ["vuex"],
        "HTTP请求": ["axios"],
        "路由管理": ["vue-router"],
        "国际化": ["vue-i18n"],
        "拖拽功能": ["vuedraggable"],
        "组合式API": ["@vue/composition-api"],
    },
    "vue3": {
        "UI组件": ["element-plus", "naive-ui", "ant-design-vue"],
        "文件上传/处理": ["vue-filepond"],
        "富文本编辑": ["@vueup/vue-quill", "@ckeditor/ckeditor5-vue"],
        "表单处理": ["vee-validate", "@vueuse/form"],
        "状态管理": ["pinia"],
        "HTTP请求": ["axios"],
        "路由管理": ["vue-router"],
        "国际化": ["vue-i18n"],
        "拖拽功能": ["vue-draggable-next"],
        "实用工具": ["@vueuse/core"],
    },
}

LANGUAGE_FEATURE_SUGGESTIONS: Dict[str, Dict[str, List[str]]] = {
    "typescript": {
        "类型支持": ["typescript", "@types/node", "tslib"],
    },
    "javascript": {
        "质量保障": ["eslint", "prettier"],
    },
}

BUILD_TOOL_FEATURE_SUGGESTIONS: Dict[str, Dict[str, List[str]]] = {
    "vite": {
        "构建优化": ["@vitejs/plugin-legacy"],
    },
    "webpack": {
        "构建优化": ["webpack-bundle-analyzer", "cross-env"],
    },
}

TARGET_PLATFORM_FEATURE_SUGGESTIONS: Dict[str, Dict[str, List[str]]] = {
    "mobile": {
        "移动端组件": ["vant", "@vant/use"],
        "触控优化": ["hammerjs"],
    },
    "desktop": {
        "桌面体验": ["electron", "electron-builder"],
    },
    "web": {
        "PWA 支持": ["workbox-window"],
    },
}

class RequirementAnalyzer:
    """需求分析器 - 使用大模型分析用户需求并返回扩展组件建议"""
    
    def __init__(self):
        # 允许通过 MODEL_PROVIDER 显式指定提供商：moonshot|deepseek
        provider = (os.getenv('MODEL_PROVIDER') or '').strip().lower()

        # 读取 Moonshot 配置
        moonshot_key = os.getenv('MOONSHOT_API_KEY')
        moonshot_base = os.getenv('MOONSHOT_BASE_URL', 'https://api.moonshot.cn/v1')
        moonshot_model = os.getenv('MOONSHOT_DEFAULT_MODEL', 'kimi-k2-0711-preview')

        # 读取 DeepSeek 配置
        deepseek_key = os.getenv('DEEPSEEK_API_KEY')
        deepseek_base = os.getenv('DEEPSEEK_BASE_URL', 'https://api.deepseek.com/v1')
        deepseek_model = os.getenv('DEEPSEEK_DEFAULT_MODEL', 'deepseek-chat')

        # 选择提供商与凭据
        if provider == 'moonshot' and moonshot_key:
            self.api_key = moonshot_key
            self.base_url = moonshot_base
            self.model = moonshot_model
        elif provider == 'deepseek' and deepseek_key:
            self.api_key = deepseek_key
            self.base_url = deepseek_base
            self.model = deepseek_model
        else:
            # 未显式指定 provider，则按优先顺序 Moonshot -> DeepSeek
            if moonshot_key:
                self.api_key = moonshot_key
                self.base_url = moonshot_base
                self.model = moonshot_model
            elif deepseek_key:
                self.api_key = deepseek_key
                self.base_url = deepseek_base
                self.model = deepseek_model
            else:
                raise ValueError("未找到有效的 API Key（请设置 MOONSHOT_API_KEY 或 DEEPSEEK_API_KEY）")

        # 清理 API key 中可能的引号
        if self.api_key.startswith('"') and self.api_key.endswith('"'):
            self.api_key = self.api_key[1:-1]
        if self.api_key.startswith("'") and self.api_key.endswith("'"):
            self.api_key = self.api_key[1:-1]
        
        self.client = OpenAI(
            api_key=self.api_key,
            base_url=self.base_url
        )
    
    def _format_feature_suggestions(self, suggestions: Dict[str, List[str]]) -> str:
        if not suggestions:
            return "- 暂无特定建议，请根据需求灵活选择组件"

        lines = []
        for feature, packages in suggestions.items():
            package_list = ", ".join(packages)
            lines.append(f"- {feature}: {package_list}")
        return "\n".join(lines)

    def _build_feature_guidance(self, framework: str, language: str, build_tool: str, target_platform: str) -> str:
        aggregated: Dict[str, List[str]] = {}

        def merge_suggestions(source: Dict[str, Dict[str, List[str]]], key: str):
            key_lower = (key or "").strip().lower()
            normalized_key = key_lower.replace(" ", "").replace("-", "").replace("@", "")
            for candidate in dict.fromkeys([key_lower, normalized_key]):
                if candidate and candidate in source:
                    for feature, packages in source[candidate].items():
                        if feature not in aggregated:
                            aggregated[feature] = []
                        for pkg in packages:
                            if pkg not in aggregated[feature]:
                                aggregated[feature].append(pkg)

        merge_suggestions(FRAMEWORK_FEATURE_SUGGESTIONS, framework)
        merge_suggestions(LANGUAGE_FEATURE_SUGGESTIONS, language)
        merge_suggestions(BUILD_TOOL_FEATURE_SUGGESTIONS, build_tool)
        merge_suggestions(TARGET_PLATFORM_FEATURE_SUGGESTIONS, target_platform)

        for feature, packages in COMMON_FEATURE_SUGGESTIONS.items():
            if feature not in aggregated:
                aggregated[feature] = []
            for pkg in packages:
                if pkg not in aggregated[feature]:
                    aggregated[feature].append(pkg)

        return self._format_feature_suggestions(aggregated)

    def _fallback_directory_structure(
        self,
        framework: str,
        base_components: List[str],
        extended_components: List[str],
    ) -> Dict[str, Any]:
        """当模型不可用时生成简单的目录结构建议"""

        is_react = (framework or "react").lower() == "react"
        src_children = [
            {
                "name": "components",
                "description": "通用 UI 组件",
                "children": [],
            },
            {
                "name": "pages" if is_react else "views",
                "description": "业务页面",
                "children": [],
            },
            {
                "name": "hooks" if is_react else "composables",
                "description": "可复用逻辑模块",
                "children": [],
            },
            {
                "name": "services",
                "description": "与后端交互的 API 封装",
                "children": [],
            },
            {
                "name": "store",
                "description": "状态管理相关模块",
                "children": [],
            },
            {
                "name": "utils",
                "description": "工具方法与常量",
                "children": [],
            },
        ]

        # 根据组件推断需要的目录
        combined = set(base_components + extended_components)
        if any("router" in comp for comp in combined):
            src_children.append(
                {
                    "name": "router",
                    "description": "应用路由配置",
                    "children": [],
                }
            )

        if any("chart" in comp or "echarts" in comp or "recharts" in comp for comp in combined):
            src_children.append(
                {
                    "name": "charts",
                    "description": "图表封装组件",
                    "children": [],
                }
            )

        if any("form" in comp or "formik" in comp or "vee" in comp for comp in combined):
            src_children.append(
                {
                    "name": "forms",
                    "description": "表单配置与校验逻辑",
                    "children": [],
                }
            )

        return {
            "summary": "根据选定组件生成的基础目录结构建议，后续可根据业务需求继续扩展。",
            "directories": [
                {
                    "name": "public",
                    "description": "静态资源与 HTML 模板",
                    "children": [],
                },
                {
                    "name": "src",
                    "description": "应用核心源代码",
                    "children": src_children,
                },
                {
                    "name": "tests",
                    "description": "单元测试与集成测试",
                    "children": [],
                },
                {
                    "name": "config",
                    "description": "构建与部署相关配置",
                    "children": [],
                },
            ],
            "used_model": False,
        }

    def generate_directory_structure(
        self,
        project_name: str,
        framework: str,
        language: str,
        build_tool: str,
        target_platform: str,
        base_components: List[str],
        extended_components: List[str],
        description: str = "",
    ) -> Dict[str, Any]:
        """利用模型或回退规则生成项目目录结构建议"""

        all_components = list(dict.fromkeys((base_components or []) + (extended_components or [])))

        feature_guidance = self._build_feature_guidance(framework, language, build_tool, target_platform)

        prompt = f"""
你是资深前端架构师，需要根据项目配置和组件清单，设计合理的项目目录结构。

项目名称：{project_name or '未命名项目'}
前端框架：{framework}
编程语言：{language}
构建工具：{build_tool}
目标平台：{target_platform}
基础组件：{', '.join(all_components) if all_components else '暂无'}
额外描述：{description or '无'}

请结合上述信息，输出 JSON，包含：
{{
  "summary": "总体说明",
  "directories": [
    {{
      "name": "目录名称",
      "description": "目录用途",
      "files": ["可选文件列表"],
      "children": [ ... 子目录 ... ]
    }}
  ]
}}

要求：
1. 根据组件类型安排必要的目录，例如状态管理、接口封装、hooks/composables、表单、图表等。
2. 目录层级不宜过深，最多 3 层。
3. 使用蛇形或短横线命名风格，与框架习惯保持一致。
4. 如果信息不足，可以给出合理假设并在描述中注明。
5. 目录结构需与 {framework} + {language} + {build_tool} 的主流实践保持一致。

针对当前配置可能涉及的功能模块：
{feature_guidance}
"""

        try:
            response = self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {
                        "role": "system",
                        "content": "你是前端架构专家，请只返回严格的 JSON，描述项目目录结构方案。",
                    },
                    {
                        "role": "user",
                        "content": prompt,
                    },
                ],
                temperature=0.3,
                max_tokens=1800,
            )

            content = response.choices[0].message.content.strip()
            start = content.find('{')
            end = content.rfind('}') + 1
            if start == -1 or end <= start:
                raise ValueError("模型未返回有效的 JSON")

            result = json.loads(content[start:end])
            result["used_model"] = True
            result["model_used"] = self.model
            result["tokens"] = response.usage.total_tokens if hasattr(response, "usage") else None
            return result
        except Exception:
            return self._fallback_directory_structure(framework, base_components or [], extended_components or [])

    def analyze_requirements(self, description: str, framework: str = 'react', language: str = 'typescript', build_tool: str = 'vite', target_platform: str = 'web', exclude_components: List[str] = None) -> Dict[str, Any]:
        """分析需求描述并返回建议的扩展组件"""
        
        if exclude_components is None:
            exclude_components = []
            
        exclude_str = f"\n\n请避免推荐以下已包含的基础组件：{', '.join(exclude_components)}" if exclude_components else ""
        feature_guidance = self._build_feature_guidance(framework, language, build_tool, target_platform)
        
        prompt = f"""
你是一个专业的前端架构师，请分析以下项目需求描述，推荐合适的 {framework} 扩展组件/库。

项目配置信息：
- 前端框架：{framework}
- 编程语言：{language}
- 构建工具：{build_tool}
- 目标平台：{target_platform}

需求描述：{description}{exclude_str}

请根据描述中的功能需求，推荐适合的 npm 包/组件库。请返回 JSON 格式：

{{
  "analysis": {{
    "detected_features": ["检测到的功能需求"],
    "complexity": "简单/中等/复杂"
  }},
  "components": [
    {{
      "name": "包名",
      "description": "功能描述", 
      "required": false,
      "version": "推荐版本"
    }}
  ]
}}

针对当前配置的功能建议：
{feature_guidance}

重要提醒：
1. 不要推荐已经在基础组件中包含的包
2. 优先推荐功能专一、维护活跃的包
3. 考虑包的大小和性能影响
4. 确保推荐的包与选择的框架和构建工具兼容
5. 根据编程语言和目标平台优化推荐
"""
        
        try:
            response = self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {
                        "role": "system",
                        "content": "你是前端架构专家，根据需求推荐组件。直接返回JSON，不要额外说明。"
                    },
                    {
                        "role": "user",
                        "content": prompt
                    }
                ],
                temperature=0.3,
                max_tokens=1500
            )
            
            content = response.choices[0].message.content.strip()
            
            # 尝试解析JSON
            try:
                result = json.loads(content)
                return {
                    "success": True,
                    "data": result,
                    "model_used": self.model,
                    "tokens": response.usage.total_tokens if hasattr(response, 'usage') else None
                }
            except json.JSONDecodeError:
                # 提取JSON部分
                start = content.find('{')
                end = content.rfind('}') + 1
                if start != -1 and end > start:
                    json_str = content[start:end]
                    result = json.loads(json_str)
                    return {
                        "success": True,
                        "data": result,
                        "model_used": self.model
                    }
                else:
                    raise ValueError("无法解析模型返回的JSON")
                    
        except Exception as e:
            return {
                "success": False,
                "error": str(e),
                "fallback_used": True
            }
